﻿using System.Collections.Generic;
using System.Threading.Tasks;
using EFCore.BulkExtensions;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using YShop.Core;
using System.Linq;
using System.Linq.Expressions;
using System;
using YShop.Application.Contracts;
using Microsoft.EntityFrameworkCore;

namespace YShop
{
    /// <summary>
    /// 主从表CURD服务1
    /// </summary>
    /// <typeparam name="TMEntity"></typeparam>
    /// <typeparam name="TSEntity"></typeparam>
    /// <typeparam name="TEntityDto"></typeparam>
    /// <typeparam name="SearchDto"></typeparam>
    /// <typeparam name="TPageSearchDto"></typeparam>
    /// <typeparam name="CreateDto"></typeparam>
    /// <typeparam name="UpdateDto"></typeparam>
    public class CrudMasterSlave1Service<TMEntity, TSEntity, TEntityDto, SearchDto, TPageSearchDto, CreateDto, UpdateDto> 
        : CrudService<TMEntity,TEntityDto, SearchDto, TPageSearchDto, CreateDto, UpdateDto>
        where TMEntity : class, IPrivateEntity, IBaseEntity, new()
        where TSEntity : class, IPrivateEntity, IBaseEntity, new()
        where TEntityDto : class, new()
        where TPageSearchDto : PageSearchDto
        where UpdateDto : BaseEntityDto

    {
        private readonly IRepository<TMEntity> _repository;
        private readonly IRepository<TSEntity> _slaveRepository;

        public CrudMasterSlave1Service(IRepository<TMEntity> repository, IRepository<TSEntity> slaveRepository) : base(repository)
        {
            _repository = repository;
            _slaveRepository = slaveRepository;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="update"></param>
        /// <returns></returns>
        [UnitOfWork]
        public override async Task UpdateAsync(List<UpdateDto> update)
        {
            var slaveDeletes = new List<TSEntity>();

            var masterType = typeof(TMEntity);
            var slaveType = typeof(TSEntity);
            var slaveIsArray = false; // 取最后的值
            var slavePropertyName = typeof(TMEntity).GetProperties().FirstOrDefault(p => 
            {
                if (p.PropertyType.IsArrayOrList())
                {
                    slaveIsArray = true;
                    var slaveType = p.PropertyType.GetGenericArguments()[0];
                    return slaveType == typeof(TSEntity);
                }
                slaveIsArray = false;
                return p.PropertyType == typeof(TSEntity);
            }).Name;

            var param = Expression.Parameter(typeof(TSEntity), "t");
            var property = Expression.Property(param, $"{masterType.Name}Id");

            foreach (var item in update)
            {
                var entity = item.Adapt<TMEntity>();
                var slaveProperty = masterType.GetProperty(slavePropertyName);
                var slaveItem = slaveProperty.GetValue(entity);
                if(slaveItem != null)
                {
                    // 如果是数组，需要先从数据库查出全部，再确定修改还是新增，删除
                    // 如果不是数组，先查，有则新增，否则修改
                    if (slaveIsArray)
                    {
                        var body = Expression.Equal(property, Expression.Constant(item.Id));
                        var query = (Expression<Func<TSEntity, bool>>)Expression.Lambda(body, param);

                        var dbSlaveItems = await _slaveRepository.Where(query, false).ToListAsync();

                        foreach(var slave in (IEnumerable<TSEntity>)slaveItem)
                        {
                            var dbSlave = dbSlaveItems.FirstOrDefault(s => s.Id == slave.Id);
                            if (dbSlave != null)
                            {
                                await _slaveRepository.UpdateAsync(slave, true);
                                dbSlaveItems.Remove(dbSlave);
                            }
                            else
                            {
                                slave.Id = Utils.NewGuid();
                                await _slaveRepository.InsertAsync(slave, true);
                            }
                        }

                        slaveDeletes.AddRange(dbSlaveItems);
                    }
                    else
                    {
                        await _slaveRepository.UpdateAsync(slaveItem.Adapt<TSEntity>(), true);
                    }
                }
                else
                {
                    var body = Expression.Equal(property, Expression.Constant(item.Id));
                    var query = (Expression<Func<TSEntity, bool>>)Expression.Lambda(body, param);

                    var dbSlave = await _slaveRepository.FirstOrDefaultAsync(query,false);

                    // 如果数据库存在，input进来的数据不存在，可认定为删除，否则为修改
                    if(dbSlave != null)
                    {
                        slaveDeletes.Add(dbSlave);
                    }
                }
                await _repository.UpdateAsync(entity,true);
            }


            if(slaveType.GetInterface("IDeleteAduitEntity") != null)
            {
                foreach (var del in slaveDeletes)
                {
                    await _slaveRepository.FakeDeleteAsync(del);
                }
            }
            else
            {
                await _slaveRepository.DeleteAsync(slaveDeletes);
            }
            UpdatedAction?.Invoke(update);
            RemoveEntitiesCache();
        }

    }
}
